一. 什么是继承
- 继承把一个原有的类的成员为己所用.
- 被继承的类叫做基类
- 新的类叫做派生类
- 继承有两种方式:- 单继承: 派生类只有一个基类
- 多继承: 派生类有多个基类
 
二. 单继承的一般形式
| 1 | class <派生类名>: <继承方式><基类名> | 
例如1
2
3
4
5
6
7
8
9
10
11
12
13
14class A
{
    public:
        seta(int x){
            a = x;
        }
    private:
        int a;
};
class B: public A
{
};
三. 派生类的访问控制
定义派生类的时候指定了<访问控制>, 访问控制包括:
- 公有继承- 基类的公有成员, 保护成员分别是派生类的公有成员, 保护成员
- 基类的私有成员, 派生类无法访问.
 
- 私有继承- 基类的公有成员和保护成员都变成派生类的私有成员
- 基类的私有成员, 派生类无法访问.
 
- 保护继承- 基类的公有成员和保护成员都变成派生类的保护成员
- 基类的私有成员, 派生类无法访问.
 
- 需要注意的地方- 基类中的私有变量, 在派生类中都无法访问. 这里就体现了保护变量的用处, 既防止在外面被调用, 又可以让派生类访问到
- 私有成员无法在派生类中访问, 但是可以在派生类中调用基类中可以访问该私有成员的方法.
- 派生类的对象都是基类的. 也就是说, 派生类的对象可以赋给基类的变量.P88
 
四. 多继承的定义格式
| 1 | class <派生类名>: <继承方式><基类名1>,...,<继承方式><基类名n> | 
例如1
2
3
4class Derivedclass: public Baseclass1, public Baseclass2
{
    ...
};
五. 二义性
- 1. 调用不同基类的相同成员时可能会出现二义性(就是所继承的时候, 多个基类之间有名字相同的成员)- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 using namespace std;
 class Baseclass1
 {
 public:
 void seta(int x){
 a = x;
 }
 void show(){
 cout<<"a = "<<a<<endl;
 }
 private:
 int a;
 };
 class Baseclass2
 {
 public:
 void setb(int x){
 b = x;
 }
 void show(){
 cout<<"b = "<<b<<endl;
 }
 private:
 int b;
 };
 class Derivedclass: public Baseclass1, public Baseclass2
 {
 public:
 void show(){
 Baseclass1::show();
 Baseclass2::show();
 }
 };
 int main()
 {
 //错误的写法
 Derivedclass obj;
 obj.seta(2);
 obj.show();//error
 obj.setb(4);
 obj.show();//不知道是哪个 show ,存在二义性, 不能编译
 //修改方法一, 使用作用域运算符
 // Derivedclass obj;
 // obj.seta(2);
 // obj.Baseclass1::show();//error
 // obj.setb(4);
 // obj.Baseclass2::show();
 //修改方法二, 重写派生类中的 show 方法
 // Derivedclass obj;
 // obj.seta(2);
 // obj.setb(4);
 // obj.show();
 return 0;
 }
- 2. 访问共同基类的成员时可能出现二义性- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 using namespace std;
 /*
 调用不同基类的相同成员可能出现二义性
 爷爷类: Base
 父类: Baseclass1, Baseclass2
 子类: Derivedclass
 爷爷类中有一个变量 val, Derivedclass 继承了两个父类, 而两个父类又都继承自爷爷类
 导致两个父类都有 val, 子类中也有, 所以存在二义性.
 解决方法是:
 Baseclass1::val
 Baseclass2::val
 错误的做法是:
 Base::val
 */
 class Base
 {
 protected:
 int val;
 };
 class Baseclass1: public Base
 {
 public:
 void seta(int x){
 val = x;
 }
 };
 class Baseclass2: public Base
 {
 public:
 void setb(int x){
 val = x;
 }
 };
 class Derivedclass: public Baseclass1, public Baseclass2
 {
 public:
 void show(){
 //cout<<"val = "<<val; //含义不清, 不能编译
 //可以这样
 cout<<"val = "<<Baseclass1::val<<endl;
 //或者
 cout<<"val = "<<Baseclass2::val<<endl;
 //这样不行
 //cout<<"val = "<<Base::val<<endl;
 }
 };
 int main()
 {
 Derivedclass obj;
 obj.seta(2);
 //obj.show();
 obj.setb(4);
 obj.show();
 return 0;
 }
- 3. 二义性检查先于访问权限检查- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 using namespace std;
 /*
 访问权限和二义性的关系
 1 里面有个 show 函数, 2 里面也有个 show 函数
 但是 1 里面的 show 是公有的, 2 里面的是私有的
 Derivedclass 继承了 1 和 2 函数, 当直接 obj.show() 的时候还是存在二义性
 所以就说明了, 通过修改成员的访问权限并没有什么卵用.
 因为二义性检查是在权限检查之前的
 */
 class Baseclass1
 {
 public:
 void seta(int x){
 a = x;
 }
 void show(){
 cout<<"a = "<<a<<endl;
 }
 private:
 int a;
 };
 class Baseclass2
 {
 public:
 void setb(int x){
 b = x;
 }
 private:
 int b;
 void show(){
 cout<<"b = "<<b<<endl;
 }
 };
 class Derivedclass: public Baseclass1, public Baseclass2
 {
 };
 int main()
 {
 Derivedclass obj;
 obj.seta(2);
 obj.setb(4);
 obj.show();
 // obj.Baseclass1::show();
 return 0;
 }
六. 虚基类
- 1. 目的- 解决二义性问题
- 使得公共基类在派生类对象中只产生一个基类子对象
 
- 2. 格式- 1 - virtual <继承方式> <基类名> - 一个派生类可以公有或私有地继承多个虚基类, virtual 和 public 的顺序无关紧要,
 但一定要放在基类名之前, 并且 virtual 只对紧随其后的基类名起作用.
 
- 一个派生类可以公有或私有地继承多个虚基类, virtual 和 public 的顺序无关紧要,
- 3. 例子- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 using namespace std;
 /*
 虚基类解决二义性问题
 爷爷类: A
 父类: B1, B2
 子类: C
 B1, B2 继承 A, C 继承了 B1, B2, A 中有一个保护变量 val
 如果不使用虚基类肯定出现二义性
 虚基类的使用方法:
 在定义派生类的时候, 加关键字 virtual
 这样一来, A 中就只有一个 val 了
 说来复杂, 在书本 98 页有张图片.
 */
 class A
 {
 public:
 void setval(int x){
 val = x;
 }
 protected:
 int val;
 };
 class B1: virtual public A
 {
 };
 class B2: virtual public A
 {
 };
 class C: public B1, public B2
 {
 public:
 void show(){
 cout<<"val = "<<val<<endl;
 }
 };
 int main()
 {
 C c;
 c.setval(5);
 c.show();
 return 0;
 }
七. 继承机制下的构造函数
- 1. 派生类中构造函数的格式- 1 
 2
 3
 4- <派生类名>::<派生类名>(总参数表): <基类名1>(参数表1),...,<基类名n>(参数表n) 
 {
 <派生类中数据成员初始化>
 }
- 2. 单继承并包括子对象时, 构造函数的调用顺序(基类 > 子对象 > 派生类)- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 using namespace std;
 /*
 有 Base1, Base2, Base3 三个类, 它们都有构造函数
 Derivedclass 继承了 Base1, 还包含了 Base2, Base3 两个子对象.
 Derivedclass 的构造函数中, 调用了另外三个类的构造函数
 顺序是: 基类, 子对象, 派生类
 注意:
 子对象构造函数的调用是根据在派生类中的声明顺序, 而不是派生类构造函数中出现的顺序
 派生类中的构造函数声明的时候可以不写出要调用的构造函数
 */
 class Base1
 {
 public:
 Base1(int i){
 a = i;
 cout<<"Base1 的构造函数被调用, 此时 a 等于: "<<a<<endl;
 }
 private:
 int a;
 };
 class Base2
 {
 public:
 Base2(int i)
 {
 b = i;
 cout<<"Base2 的构造函数被调用, 此时 b 等于: "<<b<<endl;
 }
 private:
 int b;
 };
 class Base3
 {
 public:
 Base3(int i)
 {
 c = i;
 cout<<"Base3 的构造函数被调用, 此时 c 等于: "<<c<<endl;
 }
 private:
 int c;
 };
 class Derivedclass: public Base1
 {
 public:
 Derivedclass(int i, int j, int k, int m);
 private:
 int d;
 Base2 f;
 Base3 g;
 };
 Derivedclass::Derivedclass(int i, int j, int k, int m):Base1(i),g(j),f(k)
 {
 d = m;
 cout<<"Derivedclass 的构造函数被调用, 此时 d 等于: "<<d<<endl;
 }
 int main()
 {
 Derivedclass x(5, 6, 7, 8);
 return 0;
 }
- 3. 多继承机制下构造函数的调用顺序(仍然是: 基类 > 子对象 > 派生类)- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 using namespace std;
 /*
 多继承方式下构造函数的调用顺序
 基类>子对象>派生类
 同一层次下的构造函数调用顺序取决于定义派生类时的继承顺序
 */
 class Base1
 {
 public:
 Base1(int i){
 a = i;
 cout<<"Base1 的构造函数被调用, a = "<<a<<endl;
 }
 private:
 int a;
 };
 class Base2
 {
 public:
 Base2(int i){
 b = i;
 cout<<"Base2 的构造函数被调用, b = "<<b<<endl;
 }
 private:
 int b;
 };
 class Derivedclass: public Base1, public Base2
 {
 public:
 Derivedclass(int i, int j, int k);
 private:
 int d;
 };
 Derivedclass::Derivedclass(int i, int j, int k):Base2(i),Base1(j)
 {
 d = k;
 cout<<"Derivedclass 的构造函数被调用, d = "<<d<<endl;
 }
 int main()
 {
 Derivedclass x(5, 6, 7);
 return 0;
 }
- 4. 有虚基类时, 多继承方式下构造函数的调用顺序(虚基类 > 基类 > 派生类)(但虚基类的构造函数只调用一次)- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 using namespace std;
 /*
 有虚基类时, 多继承方式下构造函数的调用顺序
 先要搞清楚几个类之间的关系, p105 有图
 方法:
 调用一个类的构造函数, 只要这个类有基类, 就一定要先调用基类的构造函数.
 调用顺序按照继承顺序, 但是虚基类最优先.
 如果虚基类已经被调用一次, 再次出现就跳过.
 */
 class Base1
 {
 public:
 Base1(){
 cout<<"Base1 的构造函数被调用."<<endl;
 }
 };
 class Base2
 {
 public:
 Base2(){
 cout<<"Base2 的构造函数被调用."<<endl;
 }
 };
 class Derived1:public Base2, virtual public Base1
 {
 public:
 Derived1(){
 cout<<"Derived1 的构造函数被调用."<<endl;
 }
 };
 class Derived2:public Base2, virtual public Base1
 {
 public:
 Derived2(){
 cout<<"Derived2 的构造函数被调用."<<endl;
 }
 };
 class Derived3: public Derived1, virtual public Derived2
 {
 public:
 Derived3(){
 cout<<"Derived3 的构造函数被调用."<<endl;
 }
 };
 int main()
 {
 Derived3 obj;
 return 0;
 }
八. 派生类构造函数的规则
- 1. 基类无, 派生类有- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 using namespace std;
 /*
 基类没有构造函数时, 派生类构造函数的规则
 (完全没规则吧???)
 */
 class Baseclass
 {
 private:
 int a;
 };
 class Derivedclass: public Baseclass
 {
 public:
 Derivedclass();
 Derivedclass(int i);
 private:
 int b;
 };
 Derivedclass::Derivedclass()
 {
 cout<<"Derivedclass 的默认构造函数被调用."<<endl;
 }
 Derivedclass::Derivedclass(int i)
 {
 b = i;
 cout<<"Derivedclass 的构造函数被调用, b = "<<b<<endl;
 }
 int main()
 {
 Derivedclass x1(5);
 Derivedclass x2;
 return 0;
 }
- 2. 基类有, 派生类无(调用派生类的默认构造函数, 然后执行基类的构造函数, 如果基类没有默认构造函数就会出错)- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 using namespace std;
 /*
 基类有构造函数, 派生类没有自定义构造函数时的规则
 派生类没有构造函数, 会调用默认的构造函数, 然后执行基类的默认构造函数
 (为防止子类没有构造函数, 父类一定要有默认构造函数???)
 */
 class Baseclass
 {
 public:
 Baseclass()
 {
 cout<<"Baseclass 默认构造函数被调用."<<endl;
 }
 Baseclass(int i)
 {
 a = i;
 cout<<"Baseclass 的构造函数被调用, a = "<<a<<endl;
 }
 private:
 int a;
 };
 class Derivedclass: public Baseclass
 {
 private:
 int b;
 };
 int main()
 {
 Derivedclass x;
 return 0;
 }
- 3. 基类有, 派生类也有- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 using namespace std;
 /*
 基类有构造函数, 派生类构造函数的规则
 如果在派生类的构造函数没有调用基类的构造函数, 那么就调用基类的默认构造函数
 如果在派生类的构造函数中调用了基类的构造函数, 那么就调用基类中对应的构造函数.
 */
 class Baseclass
 {
 public:
 Baseclass()
 {
 cout<<"Baseclass 的默认构造函数被调用."<<endl;
 }
 Baseclass(int i)
 {
 a = i;
 cout<<"Baseclass 的构造函数被调用, a = "<<a<<endl;
 }
 private:
 int a;
 };
 class Derivedclass: public Baseclass
 {
 public:
 Derivedclass(int i);
 Derivedclass(int i, int j);
 private:
 int b;
 };
 Derivedclass::Derivedclass(int i)
 {
 b = i;
 cout<<"Derivedclass 的构造函数 1 被调用, b = "<<b<<endl;
 }
 Derivedclass::Derivedclass(int i, int j): Baseclass(i)
 {
 b = j;
 cout<<"Derivedclass 的构造函数 2 被调用, b = "<<b<<endl;
 }
 int main()
 {
 Derivedclass x1(5, 6);
 Derivedclass x2(7);
 return 0;
 }
- 4. 基类无默认构造函数时, 派生类构造函数的规则- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 using namespace std;
 /*
 基类无默认构造函数时, 派生类构造函数的规则
 以下情况会出错:
 基类无默认函数, 派生类中有构造函数没有调用基类的其他构造函数
 解决方法:
 在基类中加入默认构造函数
 在派生类的所有构造函数中调用基类的构造函
 注意:
 即使没有调用派生类中那个 没有调用基类的其他构造函数的构造函数, 还是会出错.
 */
 class Baseclass
 {
 public:
 Baseclass(){};
 Baseclass(int i)
 {
 a = i;
 cout<<"Baseclass 的构造函数被调用. a = "<<a<<endl;
 }
 private:
 int a;
 };
 class Derviedclass: public Baseclass
 {
 public:
 Derviedclass(int i);
 Derviedclass(int i, int j);
 private:
 int b;
 };
 Derviedclass::Derviedclass(int i)
 {
 b = i;
 cout<<"Derviedclass 的构造函数 1 被调用, b = "<<b<<endl;
 }
 Derviedclass::Derviedclass(int i, int j):Baseclass(i)
 {
 b = j;
 cout<<"Derviedclass 的构造函数 2 被调用, b = "<<b<<endl;
 }
 int main()
 {
 Derviedclass x1(5, 6);
 //Derviedclass x2(7);
 return 0;
 }
九. 继承机制下的析构函数
刚好跟构造函数的调用顺序相反1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
using namespace std;
/*
派生类析构函数的调用顺序
刚好与构造函数的调用顺序相反, 此程序有 warning
*/
class Base1
{
public:
    Base1(int i)
    {
        a = i;
        cout<<"Base1 的构造函数被调用, a = "<<a<<endl;
    }
    ~Base1()
    {
        cout<<"Base1 的析构函数被调用."<<endl;
    }
private:
    int a;
};
class Base2
{
public:
    Base2(int i)
    {
        b = i;
        cout<<"Base2 的构造函数被调用, b = "<<b<<endl;
    }
    ~Base2()
    {
        cout<<"Base2 的析构函数被调用."<<endl;
    }
private:
    int b;
};
class Base3
{
public:
    Base3(int i)
    {
        c = i;
        cout<<"Base3 的构造函数被调用, c = "<<c<<endl;
    }
    ~Base3()
    {
        cout<<"Base3 的析构函数被调用."<<endl;
    }
private:
    int c;
};
class Derivedclass: public Base1
{
public:
    Derivedclass(int i, int j, int k, int m);
    ~Derivedclass();
private:
    int d;
    Base2 f;
    Base3 g;
};
Derivedclass::Derivedclass(int i, int j, int k, int m):Base1(i),g(j),f(k)
{
    d = m;
    cout<<"Derivedclass 的构造函数被调用, d = "<<d<<endl;
}
Derivedclass::~Derivedclass()
{
    cout<<"Derivedclass 的析构函数被调用."<<endl;
}
int main()
{
    Derivedclass x(5, 6, 7, 8);
    return 0;
}